import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Track;

import moplayer.ChordRT;
import moplayer.MyPlayerModel;
import moplayer.NoteRT;


public class MyOtherPlayer implements MyPlayerModel {

	float bpm = 120;
	final int PROGRAM = 192;
	final int NOTEON = 144;
	final int NOTEOFF = 128;
	final int SUSTAIN = 64;
	final int REVERB = 91;
	final int ON = 0, OFF = 1;
	Sequencer sequencer;
	Sequence sequence;
	Synthesizer synthesizer;
	Instrument instruments[];
	MidiChannel channels[];
	boolean record;
	Track track;
	long startTime;

	public void open() {
		try {
			if (synthesizer == null) {
				if ((synthesizer = MidiSystem.getSynthesizer()) == null) {
					System.out.println("getSynthesizer() failed!");
					return;
				}
			} 
			synthesizer.open();
			sequencer = MidiSystem.getSequencer();
			sequence = new Sequence(Sequence.PPQ, 10);
		} catch (Exception ex) { ex.printStackTrace(); return; }

		Soundbank sb = synthesizer.getDefaultSoundbank();
		if (sb != null) {
			instruments = synthesizer.getDefaultSoundbank().getInstruments();
			synthesizer.loadInstrument(instruments[0]);
		}
		MidiChannel midiChannels[] = synthesizer.getChannels();
		channels = midiChannels;

	}
	
	public MyOtherPlayer() {
		open();
	}

	@Override
	public float getBpm() {
		return this.bpm;
	}

	@Override
	public void noteOff(NoteRT note, int channel) {
		channels[channel].noteOff(note.getPitch(), note.getDynamics());
	}

	@Override
	public void noteOn(NoteRT note, int channel) {
		channels[channel].noteOn(note.getPitch(), note.getDynamics());		
	}

	@Override
	public void pause(long duration) {
		waitDuration(duration);

	}

	@Override
	public void playChord(ChordRT chord, int channel) {
		int[] notes = chord.getNotes();
		for (int i = 0; i < notes.length; i++) {
			channels[channel].noteOn(notes[i], chord.getDynamics());
		}
		waitDuration(chord.getDuration());
		for (int i = 0; i < notes.length; i++) {
			channels[channel].noteOff(notes[i], chord.getDynamics());
		}

	}

	@Override
	public void playNote(NoteRT note, int channel) {
		this.playNote(note.getPitch(), note.getDuration(), note.getDynamics(), channel);
	}

	@Override
	public void playNote(int pitch, long duration, int dynamics, int channel) {
		channels[channel].noteOn(pitch, dynamics);
		waitDuration(duration);
		channels[channel].noteOff(pitch, dynamics);
	}

	@Override
	public void setBpm(float bpm) {
		this.bpm = bpm;
	}

	@Override
	public void setCommand(int channel) {
		channels[channel].controlChange(REVERB, 127);
	}

	@Override
	public void waitDuration(long duration) {
		float f = 60000/bpm;
		float ratio = f/500.0f;
		try {
			Thread.sleep(Math.round(duration*ratio));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		MyOtherPlayer m = new MyOtherPlayer();
		m.playNote(60, 1000, 100, 5);
		m.playNote(60, 1000, 100, 5);
		m.playNote(60, 1000, 100, 5);
		m.setCommand(5);
		m.playNote(60, 1000, 100, 5);
		m.playNote(60, 1000, 100, 5);
		m.playNote(60, 1000, 100, 5);
		m.playChord(new ChordRT(ChordRT.chords[0]), 1);
	}
}
